﻿using System;

using System.Collections.Generic;
using System.Text;
using Silvermoon.Controls.Classes;
using Silvermoon.ComponentModel.Beta;
using Silvermoon.ComponentModel;

namespace Silvermoon.Controls.Beta
{
    public class ListViewItemCollection : TypedControlCollection<ListBoxBase, ItemBase>, IItemCollection
    {
        protected readonly ItemListChangedEventArgs ChangedEventArgs = new ItemListChangedEventArgs();

        public int TotalHeight
        {
            get
            {
                if (Count == 0) return 0;
                return this[Count - 1].Bottom;
            }
        }


        public ListViewItemCollection(ListBoxBase owner)
            : base(owner)
        {
        }

        protected override void OnClear()
        {
            foreach (var item in this)
            {
                item.Dispose();
            }
            base.OnClear();
            if (ListChanged != null)
            {
                ChangedEventArgs.ListChangedType = ItemListChangedType.Reset;
                ChangedEventArgs.NewIndex = 0;
                ChangedEventArgs.OldIndex = 0;
                ChangedEventArgs.OldItem = null;
                ListChanged(this, ChangedEventArgs);
            }
        }

        protected override void InsertItem(int index, ItemBase item)
        {
            item.Y = index > 0 ? this[index - 1].Bottom : 0;
            //            item.Y -= this[index].AnimatedOffset;
            base.InsertItem(index, item);
            item.Collection = this;
            ItemAdded(index, item);
            if (ListChanged != null)
            {
                ChangedEventArgs.ListChangedType = ItemListChangedType.ItemAdded;
                ChangedEventArgs.NewIndex = index;
                ListChanged(this, ChangedEventArgs);
            }
        }

        private void ItemAdded(int index, ItemBase item)
        {
            int h = item.Height + item.AnimatedOffset;
            int max = Count;
            while (++index < max)
            {
                this[index].Y += h;
            }
            UpdateListBox();
        }

        public void UpdateListBox()
        {
            this.GetListBox().InvalidateItems();
        }

        protected override void RemoveItem(int index)
        {
            ItemBase item = this[index];
            item.Collection = null;
            int h = item.Height + item.AnimatedOffset;
            base.RemoveItem(index);
            int n = Count;
            while (index < n)
            {
                this[index].Y -= h;
                index++;
            }
            UpdateListBox();
            if (ListChanged != null)
            {
                ChangedEventArgs.ListChangedType = ItemListChangedType.ItemDeleted;
                ChangedEventArgs.OldIndex = index;
                ChangedEventArgs.OldItem = item;
                ListChanged(this, ChangedEventArgs);

                //remove to allow garbage collector to remove that item:
                ChangedEventArgs.OldItem = null;
            }
        }

        public int GetItemIndexAt(int position)
        {
            if (position <= 0) return 0;
            int max = Count - 1;
            if (max < 0) return 0;
            int min = 0;
            int total = TotalHeight;
            if (position >= total) return max;

            // estimate the index by asuming that all items have the same height:
            int i = Math.Min(Count * position / total, max);

            while (min < max)
            {
                var item = this[i];
                if (item.Bottom < position) min = i + 1;
                else if (item.Top > position) max = i;
                else return i;
                i = (min + max) / 2;
            }
            return max;
        }

        public void ItemHeightChanged(ItemBase item)
        {
            int index = IndexOf(item);
            if (index < 0) return;

            int n = Count - 1;
            while (index < n)
            {
                ItemBase ib = this[index];

                this[index + 1].Y = ib.Bottom + ib.AnimatedOffset;
                index++;
            }
            UpdateListBox();
        }

        public void ItemHeightChanged(int index)
        {
            if (index < 0) return;

            int n = Count - 1;
            while (index < n)
            {
                ItemBase ib = this[index];

                this[index + 1].Y = ib.Bottom + ib.AnimatedOffset;
                index++;
            }
            UpdateListBox();
        }

        public void AddItems(params ItemBase[] items)
        {
            foreach (var item in items)
            {
                Add(item);
            }
        }

        public ListBoxBase GetListBox()
        {
            return Parent;
        }

        ItemGroupBase IItemCollection.GetItemGroup()
        {
            return null;
        }

        public event EventHandler<ItemListChangedEventArgs> ListChanged;
    }
}
